package com.tsing.cedap.common.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.*;
import org.springframework.stereotype.Component;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

@Component
public final class RedisManager {

    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    // --------------------String--------------------

    public void deleteString(String key) {
        stringRedisTemplate.delete(key);
    }

    public void deleteString(List<String> keys) {
        stringRedisTemplate.delete(keys);
    }

    public String getString(String key) {
        return stringRedisTemplate.opsForValue().get(key);
    }

    public List<String> keyPrefix(String keyPrefix) {
        return stringRedisTemplate.execute((RedisCallback<List<String>>) connection -> {
            List<String> binaryKeys = new ArrayList<>();
            Cursor<byte[]> cursor = connection.scan(new ScanOptions.ScanOptionsBuilder().match(keyPrefix + "*").count(Integer.MAX_VALUE).build());
            while (cursor.hasNext()) {
                binaryKeys.add(new String(cursor.next()));
            }
            return binaryKeys;
        });
    }

    /**
     * 存放string时，可指定有效期（秒），为0时表示永久
     */
    public void setString(String key, String value, long second) {
        if (second > 0) {
            stringRedisTemplate.opsForValue().set(key, value, second, TimeUnit.SECONDS);
        } else {
            stringRedisTemplate.opsForValue().set(key, value);
        }
    }

    /**
     * value增加increment，负数则为自减
     */
    public void addStringValue(String key, int increment) {
        stringRedisTemplate.opsForValue().increment(key, increment);
    }

    public void resetStringExpire(String key, long second) {
        stringRedisTemplate.expire(key, second, TimeUnit.SECONDS);
    }

    public boolean hasString(String key) {
        return stringRedisTemplate.hasKey(key);
    }

    // --------------------List--------------------

    public void deleteList(String key) {
        redisTemplate.delete(key);
    }

    public void deleteListByKeyLike(String key) {
        redisTemplate.delete(redisTemplate.keys(key + "*"));
    }

    public List getListAll(String key) {
        return redisTemplate.opsForList().range(key, 0, -1);
    }

    public long getListSize(String key) {
        return redisTemplate.opsForList().size(key);
    }

    /**
     * 存储在list头部
     */
    public void pushListLeft(String key, String value, long second) {
        redisTemplate.opsForList().leftPush(key, value);
        if (second > 0L) {
            redisTemplate.expire(key, second, TimeUnit.SECONDS);
        }
    }

    /**
     * 存储在list头部
     */
    public void pushListLeft(String key, List value, long second) {
        redisTemplate.opsForList().leftPushAll(key, value);
        if (second > 0L) {
            redisTemplate.expire(key, second, TimeUnit.SECONDS);
        }
    }

    /**
     * 存储在list尾部
     */
    public void pushListRight(String key, String value, long second) {
        redisTemplate.opsForList().rightPush(key, value);
        if (second > 0L) {
            redisTemplate.expire(key, second, TimeUnit.SECONDS);
        }
    }

    /**
     * 存储在list尾部
     */
    public void pushListRight(String key, List value, long second) {
        redisTemplate.opsForList().rightPushAll(key, value);
        if (second > 0L) {
            redisTemplate.expire(key, second, TimeUnit.SECONDS);
        }
    }

    public boolean hasList(String key) {
        return redisTemplate.hasKey(key);
    }

    // --------------------Set--------------------

    public void deleteSet(String key) {
        redisTemplate.delete(key);
    }

    /**
     * set移除元素
     */
    public void removeSet(String key, Object... values) {
        redisTemplate.opsForSet().remove(key, values);
    }

    public Set getSetAll(String key) {
        return redisTemplate.opsForSet().members(key);
    }

    public void setSet(String key, long second, Object... values) {
        redisTemplate.opsForSet().add(key, values);
        if (second > 0L) {
            redisTemplate.expire(key, second, TimeUnit.SECONDS);
        }
    }

    public void addSet(String key, String... values) {
        redisTemplate.opsForSet().add(key, values);
    }

    /**
     * 根据value从一个set中查询,是否存在
     */
    public Boolean hasSet(String key, Object value) {
        return redisTemplate.opsForSet().isMember(key, value);
    }

    // --------------------Map--------------------

    public void addMap(String key, Map map, long second) {
        redisTemplate.opsForHash().putAll(key, map);
        if (second > 0L) {
            redisTemplate.expire(key, second, TimeUnit.SECONDS);
        }
    }

    public Object getValueByMapKey(String key, String mapKey) {
        return redisTemplate.opsForHash().get(key, mapKey);
    }

    public boolean hasMapKey(String key, String mapKey) {
        return redisTemplate.opsForHash().hasKey(key, mapKey);
    }

    public Map getMap(String key) {
        return redisTemplate.opsForHash().entries(key);
    }

    public void setMapValue(String key, String mapKey, Object value) {
        redisTemplate.opsForHash().put(key, mapKey, value);
    }

    /**
     * 示例
     * 批量将map存入redis，或设置value的值，和批量获取map
     */
    public void fastBatchSaveMap(List<Object> list) {
        redisTemplate.executePipelined((RedisCallback<List<Object>>) connection -> {
            for (int i = 0, size = list.size(); i < size; i++) {
                connection.hSet("key".getBytes(StandardCharsets.UTF_8), "mapKey".getBytes(StandardCharsets.UTF_8), "value".getBytes(StandardCharsets.UTF_8));
            }
            return null;
        });

        List<String> keys = new ArrayList<>();
        List<Object> redisResults = redisTemplate.executePipelined((RedisCallback<Object>) connection -> {
            for (String key : keys) {
                connection.hGetAll(key.getBytes(StandardCharsets.UTF_8));
            }
            return null;
        });
    }

}
